package com.llc.spring.cloud.sdk.spring;

import com.llc.spring.cloud.sdk.common.annotation.ApiScan;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.*;

import java.util.Map;
import java.util.Set;

/**
 * time 2018/8/28 11:37
 *
 * @author xiaojie.zhu <br>
 */
@Configuration
public class InjectBeanComponent implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
    private ApplicationContext context;
    private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
    private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
    private ApiFinder apiFinder = new DefaultApiFinder();

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {

        String[] findPackage = getFindPackage();

        Set<Class<?>> classes = this.apiFinder.findApi(findPackage);
        if(classes != null && classes.size() > 0){
            for (Class<?> aClass : classes) {
                registBean(beanDefinitionRegistry, aClass);
            }
        }
    }

    private String[] getFindPackage(){
        Map<String, Object> beans = context.getBeansWithAnnotation(ApiScan.class);
        String[] packs;
        if(beans == null || beans.size() == 0){
            packs = new String[]{""};
        }else{
            if(beans.size() != 1){
                throw new RuntimeException("@ApiScan注解只能有一个，且必须有一个，现在找到:" + beans.size() + " 个 ，" + beans);
            }
            Map.Entry<String, Object> entry = beans.entrySet().iterator().next();
            Object obj = entry.getValue();
            ApiScan annotation = obj.getClass().getAnnotation(ApiScan.class);
            if(annotation == null){
                throw new NullPointerException("找不到@ApiScan");
            }
            packs = annotation.value();
        }
        return packs;
    }



    private void registBean(BeanDefinitionRegistry registry , Class<?> apiClass){
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(ApiFactoryBean.class);
        ConstructorArgumentValues constructorArgumentValues = rootBeanDefinition.getConstructorArgumentValues();
        constructorArgumentValues.addGenericArgumentValue(apiClass);

        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(rootBeanDefinition);
        rootBeanDefinition.setScope(scopeMetadata.getScopeName());

        String beanName = this.beanNameGenerator.generateBeanName(rootBeanDefinition, registry);

        BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(rootBeanDefinition, beanName);
        BeanDefinitionReaderUtils.registerBeanDefinition(beanDefinitionHolder, registry);
    }





    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}
